package com.dd.da.config.auth;

import cn.hutool.core.util.StrUtil;
import com.dd.dc.base.domain.DResult;
import com.dd.dc.common.result.ResultCode;
import com.dd.dc.utils.req.ReqUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 描述: 自定义登录成功处理类
 * extends SavedRequestAwareAuthenticationSuccessHandler
 * implements AuthenticationSuccessHandler
 * @author: yanglin
 * @Date: 2021-03-05-11:03
 * @Version: 1.0
 */
@Slf4j
@Component
public class LoginSuccessHandlerConfig implements AuthenticationSuccessHandler {

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登录成功, {}", request.getRequestURI());
        DResult result = DResult.of(null, ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());

        /**
         * 请求头：Authorization -> Basic aW50ZXJuZXRfcGx1czppbnRlcm5ldF9wbHVz 。
         * 注意是Basic 开头然后是clientid:clientScret 格式进行base64加密后的字符串。
         * clientScret需要先加密 passwordEncoder().encode("internet_plus")
         */
        String header = request.getHeader("Authorization");
        if (header == null && !header.startsWith("Basic")) {
            throw new UnapprovedClientAuthenticationException("请求投中无client信息");
        }
        String[] tokens = this.extractAndDecodeHeader(header);

        assert tokens.length == 2;

        // 获取clientId 和 clientSecret 0EC787B92416867CD5039D6CFD474B0D
        String clientId = tokens[0];
        String clientSecret = tokens[1];

        //获取 ClientDetails
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);

        if (clientDetails == null){
            throw new UnapprovedClientAuthenticationException("clientId 不存在"+clientId);
            // 判断  方言  是否一致
        }else if (!StrUtil.equals(clientDetails.getClientSecret(), clientSecret)){
            throw new UnapprovedClientAuthenticationException("clientSecret 不匹配"+clientId);
        }
        // 密码授权 模式, 组建 authentication
        TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(),"password");

        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request,authentication);

        OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
        result.setData(token);
        log.info("登录成功返回>>{}", StrUtil.toString(result));
        ReqUtil.Retuen(response, result);
    }

    /**
     * 解密请求头
     * @param header
     * @return
     */
    private String[] extractAndDecodeHeader(String header) {
        byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8);
        String base64TokenStr = header.substring(6);
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] decoded;
        try {
            // 解码
            decoded = Base64.decodeBase64(base64TokenStr);
        } catch (IllegalArgumentException var7) {
            throw new BadCredentialsException("Failed to decode basic authentication token");
        }catch (Exception e) {
            throw new BadCredentialsException("Failed to decode basic authentication token");
        }
        String token = new String(decoded, StandardCharsets.UTF_8);
        int delim = token.indexOf(":");
        if (delim == -1) {
            throw new BadCredentialsException("Invalid basic authentication token");
        } else {
            return new String[]{token.substring(0, delim), token.substring(delim + 1)};
        }
    }

}
